package com.niiwoo.civet.trade.service.local.newRefund.notify;

import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.niiwoo.civet.base.enums.RefundOrderStatusEnum;
import com.niiwoo.civet.trade.dao.entity.RefundNotifyRecord;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundNotifyRecordMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundOrderMapperExt;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyHandleResult;
import com.niiwoo.civet.trade.service.local.newRefund.notify.enums.RefundNotifyEnum;
import com.niiwoo.civet.trade.service.local.newRefund.notify.enums.RefundNotifyHandleStatusEnum;

import lombok.extern.slf4j.Slf4j;
import net.logstash.logback.encoder.org.apache.commons.lang.StringUtils;

/**
 * 还款通知门面
 * 
 * @author: kevin.jia
 * @version 1.0.0
 */
@Slf4j
@Component
public class RefundNotifyFacade {
	
	@Autowired
	private ProjectMapperExt projectMapper;
	
	@Autowired
	private RefundOrderMapperExt refundOrderMapper;
	
	@Autowired
	private RefundNotifyRecordMapperExt refundNotifyRecordMapper;
	
	@Autowired
	private RefundCommonService refundCommonService;
	
	@Autowired
	private RefundNotifyFactory refundNotifyFactory;
	
	/**
	 * 消息补偿入口
	 * 
	 * @param refundNotifyDTO
	 */
	public void notifyHandleCompensation(RefundNotifyDTO refundNotifyDTO) {
		log.info("还款消息补偿流程-消息通知处理开始，BatchNo:{}", refundNotifyDTO.getBatchNo());
		
		List<RefundNotifyRecord> refundNotifyRecordList = refundNotifyRecordMapper.selectByBatchNo(refundNotifyDTO.getBatchNo());
		if (CollectionUtils.isEmpty(refundNotifyRecordList)) {
			log.info("还款消息补偿流程-消息通知处理开始，BatchNo:{}, 本次消息记录数为空，直接跳过", refundNotifyDTO.getBatchNo());
			return;
		}
		
		Long beginTime = System.currentTimeMillis();
		
		// 默认取第一条还款记录，同一个批次标的ID与还款订单ID都是一致的
		RefundNotifyRecord refundNotifyRecord = refundNotifyRecordList.get(0);
		
		// 入口统一查询还款通用数据，避免具体消息重复查询
		refundNotifyDTO.setProjectId(refundNotifyRecord.getProjectId());
		refundNotifyDTO.setRefundOrderId(refundNotifyRecord.getRefundOrderId());
		// 设值标的信息
		refundNotifyDTO.setProject(projectMapper.selectByPrimaryKey(refundNotifyRecord.getProjectId()));
		// 设值还款订单信息
		if (null != refundNotifyRecord.getRefundOrderId() && refundNotifyRecord.getRefundOrderId() > 0) {
			refundNotifyDTO.setRefundOrder(refundOrderMapper.selectByPrimaryKey(refundNotifyRecord.getRefundOrderId()));
		}
		// 设值还款订单业务详情
		if (null != refundNotifyDTO.getRefundOrder() && RefundOrderStatusEnum.HANDLED.getCode().equals(refundNotifyDTO.getRefundOrder().getStatus())) {
			refundNotifyDTO.setRefundOrderDetailBizList(refundCommonService.getNotRefundOrderDetailBizByRefundOrderId(refundNotifyDTO.getRefundOrder().getId()));
		}
		
		log.info("还款消息补偿流程-消息通知处理开始，BatchNo:{}, 本次消息记录数：{}, 请求参数：{}", refundNotifyDTO.getBatchNo(),
				refundNotifyRecordList.size(), JSONObject.toJSONString(refundNotifyRecordList.get(0)));
		this.batchNotifyHandle(refundNotifyDTO, refundNotifyRecordList);
		log.info("还款消息补偿流程-消息通知处理结束，BatchNo:{}, 本次消息记录数：{}, 共耗时：{}mm", refundNotifyDTO.getBatchNo(), refundNotifyRecordList.size(), System.currentTimeMillis() - beginTime);
	}
	
	/**
	 * 还款流程消息处理入口
	 * 
	 * @param refundNotifyDTO
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public void notifyHandle(RefundNotifyDTO refundNotifyDTO) {
		log.info("还款消息处理流程-消息通知处理开始，BatchNo:{}");
		List<RefundNotifyRecord> refundNotifyRecordList = refundNotifyRecordMapper.selectByBatchNo(refundNotifyDTO.getBatchNo());
		if (CollectionUtils.isEmpty(refundNotifyRecordList)) {
			log.info("还款消息处理流程-消息通知处理结束，BatchNo:{}, 本次消息记录数为空，直接跳过", refundNotifyDTO.getBatchNo());			
			return;
		}
		
		Long beingTime = System.currentTimeMillis();
		log.info("还款消息处理流程-消息通知处理开始，BatchNo:{}, 处理消息记录数：{}, 消息参数：{}", refundNotifyDTO.getBatchNo(), refundNotifyRecordList.size(), 
				JSONObject.toJSONString(refundNotifyRecordList.get(0)));		
		this.batchNotifyHandle(refundNotifyDTO, refundNotifyRecordList);
		log.info("还款消息处理流程-消息通知处理结束，BatchNo:{}, 共耗时：{}mm", refundNotifyDTO.getBatchNo(), System.currentTimeMillis() - beingTime);
	}
	
	/**
	 * 按批次处理消息
	 * 
	 * @param refundNotifyDTO
	 * @param refundNotifyList
	 */
	private void batchNotifyHandle(RefundNotifyDTO refundNotifyDTO, List<RefundNotifyRecord> RefundNotifyRecordList) {
		List<Long> successHandleIdList = Lists.newArrayList();
		List<Long> failNeedCompensateIdList = Lists.newArrayList();
		List<Long> failHandleIdList = Lists.newArrayList();
		
		for (RefundNotifyRecord refundNotifyRecord : RefundNotifyRecordList) {
			// 调用单个消息处理
			RefundNotifyHandleResult refundNotifyHandleResult = practicalNotifyHandle(refundNotifyDTO, refundNotifyRecord);
			
			if (refundNotifyHandleResult.isSuccess()) {
				successHandleIdList.add(refundNotifyRecord.getId());
			} else {
				// 失败分两种情况，需要补偿的不做处理、不需要补偿的直接更新失败
				if (refundNotifyDTO.getRefundNotifyEnum().getCompensate()) {
					failNeedCompensateIdList.add(refundNotifyRecord.getId());
				} else {
					failHandleIdList.add(refundNotifyRecord.getId());
				}
			}
		}
		
		// 更新处理成功的记录
		if (CollectionUtils.isNotEmpty(successHandleIdList)) {
			refundNotifyRecordMapper.batchUpdateStatus(successHandleIdList, RefundNotifyHandleStatusEnum.HANDLE_FINISH.getStatus());
		}
		// 不需要补偿的直接更新失败
		if (CollectionUtils.isNotEmpty(failHandleIdList)) {
			refundNotifyRecordMapper.batchUpdateStatus(failHandleIdList, RefundNotifyHandleStatusEnum.HADNLE_FAIL.getStatus());
		}
		// 失败需要补偿的不做处理，待定时任务处理
		if (CollectionUtils.isNotEmpty(failNeedCompensateIdList)) {
			log.error("还款消息处理流程-批次消息通知处理部分失败，Batch:{}, failHandleId：{}", refundNotifyDTO.getBatchNo(), StringUtils.join(failNeedCompensateIdList, ","));
		}
	}
	
	/**
	 * 实际消息处理
	 * 
	 * @param refundNotifyDTO
	 * @param refundNotifyRecord
	 * @return
	 */
	RefundNotifyHandleResult practicalNotifyHandle(RefundNotifyDTO refundNotifyDTO, RefundNotifyRecord refundNotifyRecord) {
		RefundNotifyHandleResult refundNotifyHandleResult = null;
		try {
			// 根据消息类型，指定对应的消息处理服务
			RefundNotifyHandle refundNotifyService = refundNotifyFactory.create(RefundNotifyEnum.enumOf(refundNotifyRecord.getNotifyType()));
			
			// 补充内容消息
			refundNotifyDTO.setRefundNotifyEnum(RefundNotifyEnum.enumOf(refundNotifyRecord.getNotifyType()));
			refundNotifyDTO.setRefundNotifyRecord(refundNotifyRecord);
			log.info("还款消息处理流程-具体消息处理流程：{}，请求开始，RefundNotifyRecordId:{}",
					RefundNotifyEnum.enumOf(refundNotifyRecord.getNotifyType()).getDesc(), refundNotifyRecord.getId());
			refundNotifyHandleResult = refundNotifyService.handle(refundNotifyDTO);
			log.info("还款消息处理流程-具体消息处理流程：{}，请求完成，RefundNotifyRecordId:{}，返回结果：{}",
					RefundNotifyEnum.enumOf(refundNotifyRecord.getNotifyType()).getDesc(), refundNotifyRecord.getId(),
					JSONObject.toJSONString(refundNotifyHandleResult));			
		} catch (Exception e) {
			refundNotifyHandleResult = new RefundNotifyHandleResult(e.getMessage());
			log.error("还款消息处理流程-具体消息处理流程异常：{}，异常原因：{}，RefundNotifyRecordId:{}",
					RefundNotifyEnum.enumOf(refundNotifyRecord.getNotifyType()).getDesc(), e.getMessage(),
					refundNotifyRecord.getId(), e);
		}
		return refundNotifyHandleResult;
	}
}